//Class and method declarations+implementations for PGM editor
//21/03/2012
//HSXSHU003

#include <iostream>
#include <fstream>
#include <cstdlib>

namespace hsxshu003
{
 
 typedef unsigned char pixel;
 

 class PGM_editor
 {
  
	friend std::istream& operator>>(std::istream &input, PGM_editor& rhs); //declare iostream classes as friends
	friend std::ostream& operator<<(std::ostream &output, const PGM_editor& rhs);
	friend class iterator;
	
  public:
	 PGM_editor (); //constructors
	 PGM_editor (const PGM_editor& source);
	 PGM_editor& operator= (const PGM_editor& source);
	 inline pixel& operator() (const int w, const int h);


	 void set_width(int width);
	 void set_height(int height);
   
	 void invert (); //invert colours
	 void darken (int amount); //darken image by supplied value
	 void lighten (int amount); //lighten image by supplied value

	 ~PGM_editor(); //destructor
	 
	 class iterator
	 {

	  friend class PGM_editor;

	  public:
	         int x, y;
	         inline pixel& operator* () { return source.pgm_buffer[source.width * y+x]; }; //overload dereference operator

	  private:
	         iterator (PGM_editor& s) : source(s) { };//constructor
		 iterator (PGM_editor& s, int w, int h) : source(s) { source.width = w; source.height = h; };

		 PGM_editor& source; //pgm for this iterator
	 };

         PGM_editor::iterator begin (void); //iterator functions
	 PGM_editor::iterator end (void);
	 PGM_editor::iterator begin_at (int x, int y);
	 PGM_editor::iterator end_at (int x, int y);


 private:
   int width, height; //image width, image height, max value, min value, magic number
	 pixel* pgm_buffer; //image buffer pointer
   
	 std::string file; //filename
   
	 void reallocate (int w, int h) //member function which reconfigures image according to new dimensions
   {

		if (w*h != width*height)
		{
     
		 if (pgm_buffer != NULL)
		  delete[] pgm_buffer;
     
		 pgm_buffer = new pixel [w*h]; 
		
		}
    
		width = w;
		height = h;

	 };

 };

 class pixel_traits
 {
  public:
	 typedef unsigned char pixel;

	 static inline pixel min (void) {return 0;}
	 static inline pixel max (void) {return 255;}
	 static inline pixel range (void) {return max() - min(); }

	 static inline pixel invert (pixel value)
	 {
          return 255 - value;
	  //implement this bollocks

	 }

	 static pixel darken (pixel value, pixel amount)
	 {
	  
          if (amount >= value)
	   return 0;
	  else
	   return value - amount;
   //implement
	 }

	 static pixel lighten (pixel value, pixel amount)
	 {

	  if (amount >= 255-value)
	   return 255;
	  else
	   return value + amount;

   //implement
	 }
   

 };

 std::istream& operator>>(std::istream &input, PGM_editor& rhs) //overload >> operator to read from PGM file
 {	
  
	int max, w, h; //temporary variables
	char ws;
	std::string magic_number;

  input >> magic_number;

	 if (magic_number != "P5")
    exit(1);

	input >> w;
	input >> h;
	input >> max;

	rhs.reallocate(w, h);

	input >> std::ws; //wat

	input.read( (char*) rhs.pgm_buffer, rhs.width * rhs.height); //read file into buffer
	
	return input;

 }

 std::ostream& operator<<(std::ostream &output, const PGM_editor& rhs) //overload << operator to write to PGM file
 {
  
	output << "P5" << std::endl;
	output << rhs.width << " " << rhs.height << std::endl;
	output << "255"  << std::endl;
	output.write( (char*) rhs.pgm_buffer, rhs.width * rhs.height);
 
  return output;

 }


 





 


 
 




}
